package com.kx.base.util;

import java.util.concurrent.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 同步调用的工具类
 * 内部要封装线程池与CountDownLatch
 * @author Sun
 * @date 2021/8/3 22:09
 */
public class SyncBatchCallUtil {
    /**
     * 线程池
     */
    private static ExecutorService executorService;

    static {
        //核心线程数
        int corePoolSize=5;
        //最大线程数
        int maxPoolSize=10;
        //时间
        long keepAliveTime=10;
        //时间单位
        TimeUnit unit=TimeUnit.SECONDS;
        //队列
        BlockingQueue<Runnable> workQueue=new ArrayBlockingQueue<>(6);
        //默认工厂
        ThreadFactory threadFactory=new UserThreadFactory("qianfeng-countdownlatch");
        //拒绝策略
        RejectedExecutionHandler handler=new MyRejectPolicy();
        //实例化线程池
        executorService=new ThreadPoolExecutor(corePoolSize,maxPoolSize,keepAliveTime,unit,workQueue,threadFactory,handler);
    }

    /**
     * 拒绝策略
     */
    static class MyRejectPolicy implements RejectedExecutionHandler{

        @Override
        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
            System.out.println(AsyncBatchCallUtil.class.getName()+"的线程队列已经满了");
        }
    }

    /**
     * 线程工厂
     */
    static class UserThreadFactory implements ThreadFactory{

        private final String namePrefix;
        private final AtomicInteger nextId=new AtomicInteger(1);
        UserThreadFactory(String groupName){
            namePrefix="From "+ AsyncBatchCallUtil.UserThreadFactory.class.getName()+"-"+groupName+"-";
        }

        @Override
        public Thread newThread(Runnable r) {
            String name=namePrefix+nextId.getAndIncrement();
            Thread thread=new Thread(null,r,name);
            return thread;
        }
    }

    /**
     * 自定义任务类
     */
    public static abstract class Task implements Runnable{
        /**
         * 任务调度的方法
         */
        public abstract void exe();

        /**
         * 内部封装CountDownLatch
         */
        private CountDownLatch countDownLatch;

        public void setCountDownLatch(CountDownLatch countDownLatch) {
            this.countDownLatch = countDownLatch;
        }

        @Override
        public void run() {
            //先执行任务0
            try {
                exe();
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                //再让计数器-1
                countDownLatch.countDown();
            }
        }
    }


    /**
     * 创建一组任务
     */
    private static boolean createTasks(Task[] tasks){
        //给这组任务实例一个CountDownLatch
        //注意：是一组任务对应一个CountDownLatch
        //有多少个任务，计数器就是多少，所以构造方法参数为tasks.length
        CountDownLatch countDownLatch=new CountDownLatch(tasks.length);
        //给每一个任务设定相同的CountDownLatch
        for (int i = 0; i < tasks.length; i++) {
            tasks[i].setCountDownLatch(countDownLatch);
        }
        //每一个task类型其实都是Runnable类型，它应该用线程池来执行。
        for (int i = 0; i < tasks.length; i++) {
            //启动每一个任务
            executorService.execute(tasks[i]);
        }
        //卡住当前线程
        try {
            countDownLatch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    /**
     * 给外界提供可调用的方法
     * @param tasks 指定一组任务
     * @return 这组任务是否创建成功
     */
    public static boolean batch(Task ... tasks){
        return createTasks(tasks);
    }

}
